import type { SelectProps } from 'antd';
import { Select } from 'antd';
import type { BaseOptionType, DefaultOptionType } from 'antd/es/select';
import { useCallback, useEffect, useRef, useState } from 'react';

// 异步加载的下拉组件,不支持'labelInValue', 不支持维护 'loading'
interface SelectAsyncPorps<T, U extends BaseOptionType | DefaultOptionType = DefaultOptionType>
  extends Omit<SelectProps<T, U>, 'labelInValue' | 'loading' | 'options'> {
  /**
   * @desc 获取数据源的方法 初始化数据修改无效
   */
  request(): Promise<U[]>;
  /**
   * @default {open}
   */
  requestTime?: 'open' | 'init';
  /**
   * @desc 数据的缓存时间。
   * @default 5
   */
  requestCache?: number;
  requestCacheId?: string; // 缓存存放Map的id
}

export function SelectAsync<T = unknown, U extends BaseOptionType | DefaultOptionType = DefaultOptionType>(
  props: SelectAsyncPorps<T, U>,
) {
  const { value, defaultValue, request, onChange, onDropdownVisibleChange, requestCache = 5, ...res } = props;
  /**
   * @desc 初始化的默认value值
   */
  const [initValue] = useState(() => defaultValue ?? value);
  /**
   * @desc 异步数据加载中的状态
   */
  const [load, setLoad] = useState(true);
  const [options, setOptions] = useState<U[]>([]);
  const source = useRef<{ exp: number; data: U[]; getData(): void }>({
    exp: 0,
    data: [],
    getData() {
      if (source.current.exp < Date.now()) {
        setLoad(true);
        request()
          .then((data) => {
            source.current.data = data;
            source.current.exp = Date.now() + requestCache * 60 * 1000;
            setOptions(data.map((v) => ({ ...v })));
            if (typeof initValue !== 'undefined') {
              const item = data.find((v) => v.value === initValue);
              if (item) {
                onChange?.(item?.value, item);
              }
            }
          })
          .catch()
          .finally(() => {
            setLoad(false);
          });
      }
    },
  });

  useEffect(() => {
    source.current.getData();
  }, []);

  const onDdVChange = useCallback(
    (open: boolean) => {
      if (open === true) {
        source.current.getData();
      }
      onDropdownVisibleChange?.(open);
    },
    [onDropdownVisibleChange],
  );

  return (
    <Select
      value={value}
      defaultValue={initValue}
      loading={load}
      options={options}
      onDropdownVisibleChange={onDdVChange}
      onChange={onChange}
      {...res}
    ></Select>
  );
}
